/**
 * XSS防护工具类
 * 提供消息内容的XSS防护和HTML清理功能
 */

// XSS防护配置
interface XSSProtectionConfig {
  allowedTags?: string[]
  allowedAttributes?: Record<string, string[]>
  maxLength?: number
  stripScripts?: boolean
  stripEvents?: boolean
}

// 默认配置
const DEFAULT_CONFIG: Required<XSSProtectionConfig> = {
  allowedTags: ['b', 'i', 'u', 'strong', 'em', 'br', 'p', 'span'],
  allowedAttributes: {
    'span': ['class'],
    'p': ['class'],
    'strong': ['class'],
    'em': ['class']
  },
  maxLength: 10000,
  stripScripts: true,
  stripEvents: true
}

// 危险的HTML标签
const DANGEROUS_TAGS = [
  'script', 'iframe', 'object', 'embed', 'form', 'input', 'textarea', 
  'button', 'select', 'option', 'link', 'meta', 'style', 'base',
  'applet', 'body', 'html', 'head', 'title'
]

// 危险的属性
const DANGEROUS_ATTRIBUTES = [
  'onload', 'onerror', 'onclick', 'onmouseover', 'onmouseout', 'onmousedown',
  'onmouseup', 'onkeydown', 'onkeyup', 'onkeypress', 'onfocus', 'onblur',
  'onchange', 'onsubmit', 'onreset', 'onselect', 'onabort', 'onunload',
  'javascript:', 'vbscript:', 'data:', 'expression', 'behavior'
]

// URL协议白名单
const SAFE_URL_PROTOCOLS = ['http:', 'https:', 'mailto:', 'tel:']

class XSSProtection {
  private config: Required<XSSProtectionConfig>

  constructor(config: XSSProtectionConfig = {}) {
    this.config = { ...DEFAULT_CONFIG, ...config }
  }

  /**
   * 清理HTML内容，防止XSS攻击
   */
  sanitizeHTML(html: string): string {
    if (!html || typeof html !== 'string') {
      return ''
    }

    // 长度限制
    if (html.length > this.config.maxLength) {
      html = html.substring(0, this.config.maxLength)
    }

    let sanitized = html

    // 移除脚本标签
    if (this.config.stripScripts) {
      sanitized = this.removeScriptTags(sanitized)
    }

    // 移除事件处理器
    if (this.config.stripEvents) {
      sanitized = this.removeEventHandlers(sanitized)
    }

    // 移除危险标签
    sanitized = this.removeDangerousTags(sanitized)

    // 移除危险属性
    sanitized = this.removeDangerousAttributes(sanitized)

    // 清理URL
    sanitized = this.sanitizeURLs(sanitized)

    // 只保留允许的标签和属性
    sanitized = this.filterAllowedElements(sanitized)

    return sanitized
  }

  /**
   * 转义HTML特殊字符
   */
  escapeHTML(text: string): string {
    if (!text || typeof text !== 'string') {
      return ''
    }

    const htmlEscapeMap: Record<string, string> = {
      '&': '&amp;',
      '<': '&lt;',
      '>': '&gt;',
      '"': '&quot;',
      "'": '&#x27;',
      '/': '&#x2F;',
      '`': '&#x60;',
      '=': '&#x3D;'
    }

    return text.replace(/[&<>"'`=\/]/g, (match) => htmlEscapeMap[match])
  }

  /**
   * 反转义HTML特殊字符
   */
  unescapeHTML(html: string): string {
    if (!html || typeof html !== 'string') {
      return ''
    }

    const htmlUnescapeMap: Record<string, string> = {
      '&amp;': '&',
      '&lt;': '<',
      '&gt;': '>',
      '&quot;': '"',
      '&#x27;': "'",
      '&#x2F;': '/',
      '&#x60;': '`',
      '&#x3D;': '='
    }

    return html.replace(/&(?:amp|lt|gt|quot|#x27|#x2F|#x60|#x3D);/g, (match) => htmlUnescapeMap[match])
  }

  /**
   * 清理文本消息内容
   */
  sanitizeTextMessage(text: string): string {
    if (!text || typeof text !== 'string') {
      return ''
    }

    // 长度限制
    if (text.length > this.config.maxLength) {
      text = text.substring(0, this.config.maxLength)
    }

    // 转义HTML字符
    let sanitized = this.escapeHTML(text)

    // 处理换行符
    sanitized = sanitized.replace(/\r\n|\r|\n/g, '<br>')

    // 处理URL链接（可选）
    sanitized = this.linkifyURLs(sanitized)

    return sanitized
  }

  /**
   * 验证URL是否安全
   */
  isURLSafe(url: string): boolean {
    if (!url || typeof url !== 'string') {
      return false
    }

    try {
      const lowerUrl = url.toLowerCase()
      
      // Handle special protocols that don't use :// format
      if (lowerUrl.startsWith('mailto:') || lowerUrl.startsWith('tel:')) {
        const protocol = lowerUrl.split(':')[0] + ':'
        return SAFE_URL_PROTOCOLS.includes(protocol)
      }
      
      // Handle standard URLs with :// format
      if (!url.includes('://')) {
        // If it's a relative URL, it's not safe for our purposes
        return false
      }
      
      const urlObj = new URL(lowerUrl)
      return SAFE_URL_PROTOCOLS.includes(urlObj.protocol)
    } catch (error) {
      return false
    }
  }

  /**
   * 清理文件名
   */
  sanitizeFileName(fileName: string): string {
    if (!fileName || typeof fileName !== 'string') {
      return 'untitled'
    }

    // 移除危险字符
    let sanitized = fileName.replace(/[<>:"/\\|?*\x00-\x1f]/g, '_')
    
    // 限制长度
    if (sanitized.length > 255) {
      const ext = sanitized.substring(sanitized.lastIndexOf('.'))
      const name = sanitized.substring(0, 255 - ext.length)
      sanitized = name + ext
    }

    // 移除前后空格和点
    sanitized = sanitized.trim().replace(/^\.+|\.+$/g, '')

    return sanitized || 'untitled'
  }

  /**
   * 移除脚本标签
   */
  private removeScriptTags(html: string): string {
    return html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
  }

  /**
   * 移除事件处理器
   */
  private removeEventHandlers(html: string): string {
    let result = html
    
    DANGEROUS_ATTRIBUTES.forEach(attr => {
      const regex = new RegExp(`\\s*${attr}\\s*=\\s*["'][^"']*["']`, 'gi')
      result = result.replace(regex, '')
    })

    return result
  }

  /**
   * 移除危险标签
   */
  private removeDangerousTags(html: string): string {
    let result = html
    
    DANGEROUS_TAGS.forEach(tag => {
      const regex = new RegExp(`<\\/?${tag}\\b[^>]*>`, 'gi')
      result = result.replace(regex, '')
    })

    return result
  }

  /**
   * 移除危险属性
   */
  private removeDangerousAttributes(html: string): string {
    let result = html
    
    // 移除javascript:, vbscript:, data: 等危险协议
    result = result.replace(/\s*(javascript|vbscript|data):\s*[^"'\s>]*/gi, '')
    
    // 移除expression和behavior
    result = result.replace(/\s*(expression|behavior)\s*\([^)]*\)/gi, '')
    
    return result
  }

  /**
   * 清理URL
   */
  private sanitizeURLs(html: string): string {
    return html.replace(/href\s*=\s*["']([^"']+)["']/gi, (match, url) => {
      if (this.isURLSafe(url)) {
        return match
      }
      return ''
    })
  }

  /**
   * 只保留允许的元素
   */
  private filterAllowedElements(html: string): string {
    // 简单的标签过滤实现
    return html.replace(/<(\/?)([\w]+)([^>]*)>/gi, (match, slash, tagName, attributes) => {
      const tag = tagName.toLowerCase()
      
      if (!this.config.allowedTags.includes(tag)) {
        return ''
      }

      // 过滤属性
      const allowedAttrs = this.config.allowedAttributes[tag] || []
      if (allowedAttrs.length === 0) {
        return `<${slash}${tag}>`
      }

      const filteredAttrs = this.filterAttributes(attributes, allowedAttrs)
      return `<${slash}${tag}${filteredAttrs}>`
    })
  }

  /**
   * 过滤属性
   */
  private filterAttributes(attributes: string, allowedAttrs: string[]): string {
    if (!attributes.trim()) {
      return ''
    }

    const attrRegex = /(\w+)\s*=\s*["']([^"']*)["']/g
    const filteredAttrs: string[] = []
    let match

    while ((match = attrRegex.exec(attributes)) !== null) {
      const [, attrName, attrValue] = match
      if (allowedAttrs.includes(attrName.toLowerCase())) {
        filteredAttrs.push(`${attrName}="${this.escapeHTML(attrValue)}"`)
      }
    }

    return filteredAttrs.length > 0 ? ' ' + filteredAttrs.join(' ') : ''
  }

  /**
   * 将文本中的URL转换为链接
   */
  private linkifyURLs(text: string): string {
    const urlRegex = /(https?:\/\/[^\s<>"']+)/gi
    
    return text.replace(urlRegex, (url) => {
      if (this.isURLSafe(url)) {
        return `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`
      }
      return url
    })
  }

  /**
   * 检测潜在的XSS攻击
   */
  detectXSSAttempt(content: string): {
    isXSS: boolean
    riskLevel: 'low' | 'medium' | 'high'
    reasons: string[]
  } {
    const reasons: string[] = []
    let riskLevel: 'low' | 'medium' | 'high' = 'low'

    if (!content || typeof content !== 'string') {
      return { isXSS: false, riskLevel: 'low', reasons: [] }
    }

    // 检测脚本标签
    if (/<script\b/i.test(content)) {
      reasons.push('Contains script tags')
      riskLevel = 'high'
    }

    // 检测事件处理器
    const eventHandlerRegex = /on\w+\s*=/i
    if (eventHandlerRegex.test(content)) {
      reasons.push('Contains event handlers')
      riskLevel = riskLevel === 'high' ? 'high' : 'medium'
    }

    // 检测危险协议
    if (/javascript:|vbscript:|data:/i.test(content)) {
      reasons.push('Contains dangerous URL protocols')
      riskLevel = 'high'
    }

    // 检测iframe
    if (/<iframe\b/i.test(content)) {
      reasons.push('Contains iframe tags')
      riskLevel = 'high'
    }

    // 检测表达式
    if (/expression\s*\(/i.test(content)) {
      reasons.push('Contains CSS expressions')
      riskLevel = 'high'
    }

    return {
      isXSS: reasons.length > 0,
      riskLevel,
      reasons
    }
  }
}

// 创建默认实例
export const xssProtection = new XSSProtection()

// 便捷函数
export const sanitizeHTML = (html: string) => xssProtection.sanitizeHTML(html)
export const escapeHTML = (text: string) => xssProtection.escapeHTML(text)
export const sanitizeTextMessage = (text: string) => xssProtection.sanitizeTextMessage(text)
export const isURLSafe = (url: string) => xssProtection.isURLSafe(url)
export const sanitizeFileName = (fileName: string) => xssProtection.sanitizeFileName(fileName)

// 导出类型
export type { XSSProtectionConfig }